package engine.gameObject;

import static org.lwjgl.opengl.GL11.GL_MODELVIEW;
import static org.lwjgl.opengl.GL11.GL_PROJECTION;
import static org.lwjgl.opengl.GL11.glLoadIdentity;
import static org.lwjgl.opengl.GL11.glMatrixMode;

import org.lwjgl.util.glu.GLU;

/**
 * This class is used for basic camera handling. Every camera should inherit
 * from this class. It contains two panes, for different details of the scene
 * and controls for this camera. A camera is set to a scene. You can have
 * several cameras in one scene, but you can only have one active. If you want
 * to set your camera as active, call scene.setCurrentCamera(camera).
 * 
 * @author Richard
 * 
 */
public abstract class Camera {

	//values to define the two frustums. 
	private float openAngle;
	private float near;
	private float nearPane;
	private float farPane;
	
	//current position of the camera. 
	private float eyeX;
	private float eyeY;
	private float eyeZ;
	
	//This is the position, the camera is looking at. 
	private float lookAtX;
	private float lookAtY;
	private float lookAtZ;
	
	//This is the up vector of the camera. 
	private float upX;
	private float upY = 1;
	private float upZ;
	
	//Width and height of the screen. This is important for setting the correct ratio. These values are applied by the core. 
	private int width;
	private int height;
	
	/**
	 * Preparing the projection matrix for the near pane. 
	 */
	public void prepareNearPane() {
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		GLU.gluPerspective(openAngle, width / (float) height, near,
				nearPane);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
	}
	
	/**
	 * Preparing the projection matrix for the far pane. 
	 */
	public void prepareFarPane() {
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		GLU.gluPerspective(openAngle, width / (float) height, near,
				farPane);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
	}
	
	/**
	 * Make the modelview matrix look at the specified camera position. 
	 */
	public void look() {
		GLU.gluLookAt(eyeX, eyeY, eyeZ, lookAtX, lookAtY, lookAtZ, upX, upY, upZ);
	}
	
	public abstract void update(float timeElapsed);

	public float getOpenAngle() {
		return openAngle;
	}

	public void setOpenAngle(float openAngle) {
		this.openAngle = openAngle;
	}

	public float getNear() {
		return near;
	}

	public void setNear(float near) {
		this.near = near;
	}

	public float getNearPane() {
		return nearPane;
	}

	public void setNearPane(float nearPane) {
		this.nearPane = nearPane;
	}

	public float getFarPane() {
		return farPane;
	}

	public void setFarPane(float farPane) {
		this.farPane = farPane;
	}
	
	public void setWidth(int width) {
		this.width = width;
	}
	
	public int getWidth() {
		return width;
	}
	
	public int getHeight() {
		return height;
	}
	
	public void setHeight(int height) {
		this.height = height;
	}
	
	public void keyPressed(int key){}
	
	public void keyReleased(int key){}
	
	public void mousePressed(int posX, int posY, int button) {}
	
	public void mouseReleased(int posX, int posY, int button) {}
	
	public void mouseMoved(int posX, int posY, int button) {}
	
	public void mouseDragged(int posX, int posY, int button) {}
	
	public void mouseWheelMoved(int movement) {}

	public float getEyeX() {
		return eyeX;
	}

	public void setEyeX(float eyeX) {
		this.eyeX = eyeX;
	}

	public float getEyeY() {
		return eyeY;
	}

	public void setEyeY(float eyeY) {
		this.eyeY = eyeY;
	}

	public float getEyeZ() {
		return eyeZ;
	}

	public void setEyeZ(float eyeZ) {
		this.eyeZ = eyeZ;
	}

	public float getLookAtX() {
		return lookAtX;
	}

	public void setLookAtX(float lookAtX) {
		this.lookAtX = lookAtX;
	}

	public float getLookAtY() {
		return lookAtY;
	}

	public void setLookAtY(float lookAtY) {
		this.lookAtY = lookAtY;
	}

	public float getLookAtZ() {
		return lookAtZ;
	}

	public void setLookAtZ(float lookAtZ) {
		this.lookAtZ = lookAtZ;
	}

	public float getUpX() {
		return upX;
	}

	public void setUpX(float upX) {
		this.upX = upX;
	}

	public float getUpY() {
		return upY;
	}

	public void setUpY(float upY) {
		this.upY = upY;
	}

	public float getUpZ() {
		return upZ;
	}

	public void setUpZ(float upZ) {
		this.upZ = upZ;
	}
	
	public void setUp(float x, float y, float z) {
		upX = x;
		upY = y;
		upZ = z;
	}
}
